Title Banner

Previous Book Contents Book Index Next

Inside Macintosh: QuickDraw GX Graphics /
Chapter 2 - Geometric Shapes / Using Geometric Shapes


Creating and Drawing Paths

Like a polygon contour, a path contour is a series of connected points. However, whereas a polygon contour is made up of straight lines, a path contour can contain both straight lines and curves. Therefore, the geometric points that make up a path contour can be on-curve points or off-curve control points. QuickDraw GX defines the gxPath structure to encapsulate a path contour geometry:

struct gxPath {
   long           vectors;
   long           controlBits[gxAnyNumber];
   struct gxPoint vector[gxAnyNumber];
};
The vectors field indicates the number of geometric points in the path and the vector array contains the geometric points themselves. The controlBits array specifies which geometric points are on-curve points and which are off-curve control points. A value of 0 indicates an on-curve point and a value of 1 indicates an off-curve point. For example, a controlBits field with the value

0x55555555   /* 0101 0101 0101 0101 ... */
indicates that every other point is an off-curve control point; the first point is on curve, the second point is off, and so on. As another example, a controlBits field value of

0x00000000   /* 0000 0000 0000 0000 ... */
indicates all points are on curve, which effectively creates a polygon.

Notice that the controlBits array allows you to specify sequential off-curve control points. For example, a controlBits value of

0xFFFFFFFF   /* 1111 1111 1111 1111 ... */
indicates that all points are off curve. When you indicate that two control points in a row are off curve, QuickDraw GX assumes an on-curve point midway between them. (The example in Listing 2-17 on page 2-59 gives an example.)

Like the polygon shape, the path shape allows you to group any number of contours within a single QuickDraw GX shape. The gxPaths structure encapsulates the multiple-path geometry:

struct gxPaths {
   long          contours;
   struct gxPath contour[gxAnyNumber];
};
The contours field indicates the total number of contours (in other words, the total number of separate paths), and the contour array contains the path geometries.

Creating Paths With a Single Contour

Since a gxPaths structure is of variable length and every element in it is of type long, you can define a path geometry as an array of long values. The sample function in Listing 2-16 shows how to define a path geometry as an array of long values, and then draw a path shape using the GXDrawPaths function. Since the GXDrawPaths function expects its first parameter to be a pointer to a gxPaths structure, the sample function casts the array of long values to the appropriate type using the expression

(gxPaths *) aPathGeometry
before sending the information to the GXDrawPaths function.

Listing 2-16 Drawing a path shape

void DrawAPathShape(void)
{
   static long aPathGeometry[] = {1, /* number of contours */
                                  6, /* number of points */
                                  0x48000000, /* 0100 1000 */
                                  ff(50), ff(100),   /* on */
                                  ff(0), ff(75),     /* off */
                                  ff(50), ff(50),    /* on */
                                  ff(150), ff(50),   /* on */
                                  ff(200), ff(75),   /* off */
                                  ff(150), ff(100)}; /* on */
                                 
   
   GXDrawPaths((gxPaths *) aPathGeometry, gxOpenFrameFill);
}
The path defined in this example has four on-curve points and two off-curve points. When drawn with the open-frame shape fill, it contains two curves and one straight line, as shown in Figure 2-33.

Figure 2-33 A path

The sample function from Listing 2-16 draws the path without creating a path shape. It could instead create a path shape with the GXNewPaths function:

aPathsShape = GXNewPaths((gxPaths *) aPathGeometry);
and then draw it using the GXDrawShape function:

GXDrawShape(aPathsShape);
You can also create path shapes using the GXNewShape function:

aPathsShape = GXNewShape(gxPathType);
GXSetPaths(aPathsShape, (gxPaths *) aPathGeometry);
or by using the GXNewShapeVector function:

aPathsShape = GXNewShapeVector(gxPathType, aPathGeometry);
Notice that in this case you do not have to cast the aPathGeometry array to be a pointer to a gxPaths structure. The GXNewShapeVector function expects an array of long values.

Although the GXDrawPaths function (shown in Listing 2-16) allows you to specify a shape fill, the GXDrawShape function does not. If you create a path shape and you want it to have a different shape fill than the default path shape, you must indicate the desired shape fill using the GXSetShapeFill function--for example,

GXSetShapeFill(aPathsShape, gxInverseEvenOddFill);
For more information about shape fills, see "Shape Fill" beginning on page 2-12.

Creating Paths Using Only Off-Curve Points

The sample function in Listing 2-17 shows how you can create a path using only off-curve control points. The path defined in this example contains four control points, and the controlBits field is set to

0xF0000000    /* 1111 0000 0000 0000 0000 ... */
which indicates that the first four points are off curve. The path contains only four points, and therefore they are all off curve.

Listing 2-17 Creating a path using only off-curve control points

void CreateRoundPath(void)
{
   gxShape     aPathShape;
   
   static long aPathGeometry[] = {1, /* number of contours */
                                  4, /* number of points */
                                  0xF0000000, /* 1111 0000 ... */
                                  ff(50), ff(50),   /* off */
                                  ff(150), ff(50),  /* off */
                                  ff(150), ff(150), /* off */
                                  ff(50), ff(150)}; /* off */
                                 
      
   aPathShape = GXNewPaths((gxPaths *) aPathGeometry);

   GXDrawShape(aPathShape);
}
The four off-curve control points in this example form a square; the path that they define is a rounded square, as shown in Figure 2-34.

Figure 2-34 A round path shape

Notice that the path is filled with the even-odd shape fill, which is the default for path shapes. You could, however, specify any shape fill for this path except the open-frame shape fill. The open-frame shape fill requires that the first and last points of the contour be on-curve points, and this path has no on-curve points.

Creating Paths With Multiple Contours

The sample function in Listing 2-18 shows how a single path shape can contain more than one path contour. The path shape defined in this example includes the round path from the previous example as well as a second round path, entirely contained within the first.

Listing 2-18 Creating a path with concentric contours

void CreateHollowCircles(void)
{
   gxShape  aPathShape;
   
   static long aPathGeometry[] = {2, /* number of contours */
                                  4, /* number of points */
                                  0xF0000000, /* 1111 0000 ... */
                                  ff(50), ff(50),   /* off */
                                  ff(150), ff(50),  /* off */
                                  ff(150), ff(150), /* off */
                                  ff(50), ff(150),  /* off */

                                  4, /* number of points */
                                  0xF0000000, /* 1111 0000 ... */
                                  ff(65), ff(65),   /* off */
                                  ff(135), ff(65),  /* off */
                                  ff(135), ff(135), /* off */
                                  ff(65), ff(135)}; /* off */
                           
      
   aPathShape = GXNewPaths((gxPaths *) aPathGeometry);
   GXSetShapeFill(aPathShape, gxClosedFrameFill);

   GXDrawShape(aPathShape);

   GXDisposeShape(aPathShape);
}
The result of this function is shown in Figure 2-35.

Figure 2-35 A path shape with two concentric clockwise contours and closed-frame shape fill

You can change the shape fill of this polygon by removing this line of code from the sample function in Listing 2-18:

GXSetShapeFill(aPolygonsShape, gxClosedFrameFill);
If you don't specify a shape fill, the GXNewPaths function uses the shape fill from the default path shape, which is the even-odd shape fill (unless you change it using the GXGetDefaultShape and GXSetShapeFill functions). The path shape resulting from an even-odd shape fill is shown in Figure 2-36.

Figure 2-36 A path shape with two concentric clockwise contours and even-odd shape fill

Notice that the even-odd shape fill causes QuickDraw GX to fill in the outer contour, but not the inner contour. However, if you specify the winding shape fill for this path using the call

GXSetShapeFill(aPathShape, gxWindingFill);
the resulting shape would appear as shown in Figure 2-37.

Figure 2-37 A path shape with two concentric clockwise contours and winding shape fill

Unlike the even-odd shape fill, the winding shape fill causes QuickDraw GX to fill inner contours--as long as the inner contour has the same contour direction as the outer contour. If the inner contour and the outer contour have opposite contour directions, neither the even-odd shape fill nor the winding shape fill will fill the inner contour.

For example, if you change the direction of the inner contour from the previous example by reversing the order of the second path's geometric points, as in the declaration

static long aPathGeometry[] = {2, /* number of contours */
                               4, /* number of points */
                               0xF0000000, /* 1111 0000 */
                               ff(50), ff(50),    /* off */ 
                               ff(150), ff(50),   /* off */ 
                               ff(150), ff(150),  /* off */ 
                               ff(50), ff(150),   /* off */ 

                               4, /* number of points */
                               0xF0000000, /* 1111 0000 */
                               ff(65), ff(135),   /* off */ 
                               ff(135), ff(135),  /* off */ 
                               ff(135), ff(65),   /* off */ 
                               ff(65), ff(65)};   /* off */
and set the shape fill to the closed-frame shape fill using the call

GXSetShapeFill(aPathShape, gxClosedFrameFill);
the resulting shape has contours with opposite contour directions, as depicted in
Figure 2-38.

Figure 2-38 A path shape with an internal counterclockwise contour and closed-frame shape fill

Since the outer contour and the inner contour have opposite contour directions, neither the even-odd shape fill nor the winding shape fill cause QuickDraw GX to fill the inner contour, as shown in Figure 2-39.

Figure 2-39 A path shape with even-odd or winding shape fill

For more information about contour direction and shape-filling algorithms, see "Shape Fill" on page 2-12.

For more information about path shapes, see "Path Shapes" on page 2-25 and "Path Structures" on page 2-107.

For information about the functions you can use to create and draw paths, see the description of the GXNewPaths function on page 2-117 and the GXDrawPaths function on page 2-162.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
7 JUL 1996




Navigation graphic, see text links

Main | Page One | What's New | Apple Computer, Inc. | Find It | Contact Us | Help